package com.fa4j.system.account.service.impl;

import com.fa4j.common.base.model.CommonState;
import com.fa4j.system.account.model.*;
import com.fa4j.system.account.repository.AccountBindRepository;
import com.fa4j.system.account.repository.AccountRepository;
import com.fa4j.system.account.service.AccountBindService;
import com.fa4j.system.account.service.AccountService;
import com.fa4j.third.user.model.ThirdOauth2UserInfo;
import com.fa4j.third.user.model.ThirdOauth2UserToken;
import com.fa4j.third.user.model.ThirdUserAccessTokenCmd;
import com.fa4j.third.user.model.ThirdUserGetCmd;
import com.fa4j.third.user.service.ThirdUserOauth2Service;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
 * 账号绑定 服务接口实现
 *
 * @since 2025-05-06 16:16:26
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class AccountBindServiceImpl implements AccountBindService {

    private final ThirdUserOauth2Service thirdUserOauth2Service;
    private final AccountService accountService;

    private final AccountBindRepository accountBindRepository;
    private final AccountRepository accountRepository;

    /**
     * 绑定账号
     *
     * @param cmd 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountBind bind(@Valid AccountBindCmd cmd) {
        AccountBind bind = queryThirdBind(cmd);//授权码authCode 换取三方账号信息
        Optional<AccountBind> bindOpt = accountBindRepository.findAccountByOpenId(bind.getAppType(), bind.getType(), bind.getThirdAppId(), bind.getThirdOpenId());
        if (bindOpt.isPresent()) {
            if (!ObjectUtils.isEmpty(cmd.getAccountId()) && !Objects.equals(cmd.getAccountId(), bindOpt.get().getAccountId())) {
                throw AccountBindError.ACCOUNT_BIND_OTHER.build();  //账号已被绑定
            }
            bind.setAccountId(bindOpt.get().getAccountId());
            accountBindRepository.modify(bind);
            return bindOpt.get();
        }
        if (!ObjectUtils.isEmpty(bind.getThirdUnionId())) {
            List<AccountBind> bindList = accountBindRepository.queryAccountByUnionId(bind.getAppType(), bind.getType(), bind.getThirdUnionId());
            if (!bindList.isEmpty()) {
                Long bindAccountId = bindList.get(0).getAccountId();
                if (!ObjectUtils.isEmpty(cmd.getAccountId()) && !Objects.equals(cmd.getAccountId(), bindAccountId)) {
                    throw AccountBindError.ACCOUNT_BIND_OTHER.build();  //账号已被绑定
                }
                bind.setAccountId(bindAccountId);
            }
        }
        Account account = null;
        if (!ObjectUtils.isEmpty(bind.getAccountId())) {
            account = accountRepository.findById(cmd.getAccountId()).orElse(null);
        }
        if (account == null && !ObjectUtils.isEmpty(cmd.getPhone())) {
            account = accountRepository.findByPhone(cmd.getAppType(), cmd.getPhone()).orElse(null);
        }
        if (account == null && !ObjectUtils.isEmpty(bind.getExt().getPhone())) {
            account = accountRepository.findByPhone(cmd.getAppType(), bind.getExt().getPhone()).orElse(null);
        }
        if (account != null && account.getState() == CommonState.DISABLE) {
            throw AccountBindError.ACCOUNT_DISABLE.build(); //账号已被禁用
        }
        if (account == null && cmd.isRegisterEnable()) {
            account = createAccount(cmd, bind);
        }
        if (account == null) {
            throw AccountBindError.ACCOUNT_NOT_BIND.build();
        }
        bind.setAccountId(account.getId());
        bind.setOperatorId(account.getId());
        accountBindRepository.create(bind);
        return bind;
    }

    private Account createAccount(AccountBindCmd cmd, AccountBind bind) {
        AccountCreateCmd accountCreateCmd = new AccountCreateCmd();
        accountCreateCmd.setAppType(bind.getAppType());
        if (cmd.getPhone() != null) {
            accountCreateCmd.setPhone(cmd.getPhone());
            accountCreateCmd.setUsername(cmd.getPhone());
        } else if (bind.getExt().getPhone() != null) {
            accountCreateCmd.setPhone(bind.getExt().getPhone());
            accountCreateCmd.setUsername(bind.getExt().getPhone());
        }
        if (bind.getExt().getNickname() != null) {
            accountCreateCmd.setNickname(bind.getExt().getNickname());
        }
        accountCreateCmd.setType(AccountType.NORMAL);
        accountCreateCmd.setState(CommonState.ENABLE);
        accountCreateCmd.setEmail(bind.getExt().getEmail());

        if (accountCreateCmd.getUsername() == null) {
            accountCreateCmd.setUsername(UUID.randomUUID().toString());
        }
        if (accountCreateCmd.getNickname() == null) {
            accountCreateCmd.setNickname(accountCreateCmd.getUsername());
        }
        accountCreateCmd.setOperatorId(0L);
        return accountService.create(accountCreateCmd);
    }

    private AccountBind queryThirdBind(AccountBindCmd cmd) {
        AccountBind bindInfo = new AccountBind();

        bindInfo.setAppType(cmd.getAppType());
        bindInfo.setAccountId(cmd.getAccountId());
        bindInfo.setType(cmd.getLoginType());
        ThirdUserAccessTokenCmd thirdCmd = new ThirdUserAccessTokenCmd();
        thirdCmd.setCode(cmd.getThirdCode());
        thirdCmd.setBizCode(cmd.getLoginType().getThirdBizCode());
        ThirdOauth2UserToken userOauth2Token = thirdUserOauth2Service.getAccessToken(thirdCmd);
        bindInfo.setThirdAppId(userOauth2Token.getAppId());
        bindInfo.setThirdOpenId(userOauth2Token.getOpenId());
        bindInfo.setThirdUnionId(userOauth2Token.getUnionId());
        AccountBindExt bindExt = new AccountBindExt();
        bindExt.setAccessToken(userOauth2Token.getAccessToken());
        bindExt.setRefreshToken(userOauth2Token.getRefreshToken());
        bindExt.setTokenExpiredTime(userOauth2Token.getExpiredTime());
        bindInfo.setExt(bindExt);
        if (userOauth2Token.getOpenId() == null) {
            // 如果不能获取openId 则需要查询用户信息
            ThirdUserGetCmd userGetCmd = new ThirdUserGetCmd();
            userGetCmd.setAccessToken(userOauth2Token.getAccessToken());
            userGetCmd.setBizCode(cmd.getLoginType().getThirdBizCode());
            ThirdOauth2UserInfo userInfo = thirdUserOauth2Service.getUserInfo(userGetCmd);
            bindExt.setPhone(userInfo.getMobile());
            bindInfo.setThirdAppId(userInfo.getAppId());
            bindInfo.setThirdOpenId(userInfo.getOpenId());
            bindInfo.setThirdUnionId(userInfo.getUnionId());
        }
        return bindInfo;
    }

    /**
     * 解除绑定
     *
     * @param cmd 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbind(AccountUnBindCmd cmd) {
        List<AccountBind> bindList = accountBindRepository.queryByAccountIdAndType(cmd.getAccountId(), cmd.getLoginType());
        for (AccountBind bind : bindList) {
            if (cmd.getId() != null && !cmd.getId().equals(bind.getId())) {
                continue;
            }
            bind.setOperatorId(cmd.getOperatorId());
            accountBindRepository.remove(bind);
        }
    }

}




